package com.jackstraw.jack_base.remote_command.service.impl;

import com.jackstraw.jack_base.remote_command.entity.BeforeAfterEnum;
import com.jackstraw.jack_base.remote_command.entity.Conn;
import com.jackstraw.jack_base.remote_command.entity.InstallProperties;
import com.jackstraw.jack_base.remote_command.entity.ModelEnum;
import com.jackstraw.jack_base.remote_command.entity.NonPasswordProperties;
import com.jackstraw.jack_base.remote_command.pool.entity.SessiontConnectionConfig;
import com.jackstraw.jack_base.remote_command.service.JschService;
import com.jackstraw.jack_base.util.FileUtil;
import com.jackstraw.jack_base.util.StringUtil;
import com.jackstraw.jack_base.remote_command.config.JschConfig;
import com.jackstraw.jack_base.remote_command.entity.JackSoftProperties;
import com.jackstraw.jack_base.remote_command.service.GroupControlService;
import com.jackstraw.jack_base.util.SpringUtil;
import com.jackstraw.jack_base.util.exception.BadRequestException;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ObjectUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.Resource;
import org.springframework.core.io.ResourceLoader;

import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;


@Slf4j
public abstract class AbstractGroupControlServiceImpl implements GroupControlService {

    public final static String GROUP_CONTROL_SERVICE_IMPL = "GroupControlServiceImpl";
    public final static String INSTALL_PATH_PARTEN = "classpath:install/container/";
    public final static String BEAN_NAME = "GroupControlServiceImpl";
    public final static String INSTALL_FILE_NAME = "install.sh";
    public final static String INSTALL_BEFORE_FILE_NAME = "install.sh";
    public final static String NOTE_FILE = "note.jack";
    public final static String BINARY_FILE = "binary";
    public final static String DOCKER_MYSQL_SCRIPT_PATH = "/data/docker/mysql8/script/";
    private final Lock lock = new ReentrantLock();

    @Override
    public Lock getLock() {
        return lock;
    }

    @Autowired
    private JschService jschService;

    @Autowired
    private ResourceLoader resourceLoader;

    private JschConfig jschConfig;

    private Map<String, JackSoftProperties.SoftProperties> jackSoftPropertiesMap;

    public AbstractGroupControlServiceImpl(JschConfig jschConfig) {
        this.jschConfig = jschConfig;
        this.jackSoftPropertiesMap = jschConfig.getJackSoftPropertiesMap();
    }

    @Override
    public ResourceLoader getResourceLoader() {
        return resourceLoader;
    }

    @Override
    public JschConfig getJschConfig() {
        return jschConfig;
    }

    @Override
    public JschService getJschService() {
        return this.jschService;
    }


    @Override
    public Map<String, JackSoftProperties.SoftProperties> getJackSoftPropertiesMap() {
        return jackSoftPropertiesMap;
    }

    @Override
    public void uploadConfig(InstallProperties installProperties) throws Exception {
        String directory = installProperties.getDirectory();
        String installName = installProperties.getInstallName();
        String dockerComposeName = "docker-compose-".concat(installName).concat(".yml");
        String connName = installProperties.getConnName();
        String rootConnName = SessiontConnectionConfig.getRootConnName(connName);
        //类似于  classpath:install/container//mysql/single
        String localScriptPath = installProperties.getLocalScriptPath();
        String localDbScriptPath = installProperties.getLocalScriptPath().concat("/db");
        String localBinaryFilePath = installProperties.getLocalScriptPath().concat("/").concat(BINARY_FILE);
        Resource resource = this.getResourceLoader().getResource(localScriptPath);
        File file = resource.getFile();
        Map<String, List<File>> fileMap = FileUtil.fileAll(file, localScriptPath);
        Map<String, String> jackDictPropertiesMap = this.getJschConfig().getJackDictPropertiesMap()
                .get(connName);
        fileMap.keySet().stream().forEach(filePathSon -> {
            fileMap.get(filePathSon).stream().forEach(fileSon -> {
                try {
                    String fileSonName = fileSon.getName();
                    //filePathSon
                    //classpath:install/container/mysql/cluster/1/
                    //classpath:install/container/mysql/cluster/1//mysql8
                    //要上传的文件为：  classpath:install/container/mysql/cluster/1/docker-compose-mysql.yml
                    String localScriptPathSon = filePathSon.concat("/").concat(fileSonName);
                    Resource resourceSon = this.getResourceLoader().getResource(localScriptPathSon);
                    InputStream inputStream = resourceSon.getInputStream();
                    if (dockerComposeName.equals(fileSonName)) {
                        this.getJschService().upload(Conn.buildSftp(rootConnName), DockerGroupControlServiceImpl.DOCKER_PATH, inputStream, fileSonName);
                    } else if (INSTALL_FILE_NAME.equals(fileSonName)) {
                        String newScriptDirectoryPath = directory.concat("/install/").concat(installName);
                        this.getJschService().uploadReplace(Conn.buildSftp(rootConnName), newScriptDirectoryPath, inputStream, fileSonName, jackDictPropertiesMap);
                        String installScriptPath = newScriptDirectoryPath.concat("/").concat(fileSonName);
                        this.getJschService().chmodInstall(Conn.buildSftp(rootConnName), installScriptPath);
                        installProperties.setInstallScriptPath(installScriptPath);
                        installProperties.setInstallFlag(Boolean.TRUE);
                    } else if (INSTALL_BEFORE_FILE_NAME.equals(fileSonName)) {
                        String newScriptDirectoryPath = directory.concat("/install/").concat(installName);
                        this.getJschService().uploadReplace(Conn.buildSftp(rootConnName), newScriptDirectoryPath, inputStream, fileSonName, jackDictPropertiesMap);
                        String installScriptPath = newScriptDirectoryPath.concat("/").concat(fileSonName);
                        this.getJschService().chmodInstall(Conn.buildSftp(rootConnName), installScriptPath);
                        installProperties.setInstallBeforeScriptPath(installScriptPath);
                        installProperties.setInstallBeforeFlag(Boolean.TRUE);
                    } else if (NOTE_FILE.equals(fileSonName)) {
                        installProperties.getNoteMap().put(connName, this.readInputStream(fileSon));
                        String newScriptDirectoryPath = directory.concat("/install/").concat(installName);
                        this.getJschService().uploadReplace(Conn.buildSftp(rootConnName), newScriptDirectoryPath, inputStream, fileSonName,jackDictPropertiesMap);
                    } else if (filePathSon.startsWith(localDbScriptPath)) {
                        //说明是SQL脚本文件
                        String directoryDbScriptPath = DOCKER_MYSQL_SCRIPT_PATH.concat(installName);
                        this.getJschService().upload(Conn.buildSftp(rootConnName), directoryDbScriptPath, inputStream, fileSonName);
                        String dbSriptPath = directoryDbScriptPath.concat("/").concat(fileSonName);
                        this.getJschService().chmodAllInstall(Conn.buildSftp(rootConnName), dbSriptPath);
                        installProperties.getDbScriptPathList().add(dbSriptPath);
                        installProperties.setInstallDbFlag(Boolean.TRUE);
                    } else if (filePathSon.startsWith(localBinaryFilePath)) {
                        String newDirectory = directory.concat(filePathSon.replace(localBinaryFilePath, ""));
                        this.getJschService().notUnixUpload(Conn.buildSftp(rootConnName), newDirectory, inputStream, fileSonName);
                    } else {
                        String newDirectory = directory.concat(filePathSon.replace(localScriptPath, ""));
                        this.getJschService().uploadReplace(Conn.buildSftp(rootConnName), newDirectory, inputStream, fileSonName, jackDictPropertiesMap);
                    }
                } catch (Exception e) {
                    throw new RuntimeException(e);
                }
            });
        });
    }


    @Override
    public void install(InstallProperties installProperties) throws Exception {
        installProperties.setLocalScriptPath(INSTALL_PATH_PARTEN.concat(installProperties.getInstallName()));
        if (ModelEnum.single.equals(installProperties.getModelEnum())) {
            installProperties.setLocalScriptPath(installProperties.getLocalScriptPath().concat("/").concat(ModelEnum.single.getCode()));
            this.installSingle(installProperties);
        } else if (ModelEnum.cluster.equals(installProperties.getModelEnum())) {
            installProperties.setLocalScriptPath(
                    installProperties.getLocalScriptPath().concat("/").concat(ModelEnum.cluster.getCode()).concat("/"));
            this.installCluster(installProperties);

        } else {
            throw new BadRequestException("3200000002", "软件搭建模式不正确");
        }
    }

    @Override
    public void installSingle(InstallProperties installProperties) throws Exception {
        String installName = installProperties.getInstallName();
        //上传所需配置文件
        long startTime = System.currentTimeMillis();
        log.info("安装{}上传配置文件开始,开始时间为：{}", installName, startTime);
        this.uploadConfig(installProperties);
        long endTime = System.currentTimeMillis();
        log.info("安装{}上传配置文件结束,结束时间为：{},共用时：{}毫秒", installName, endTime, endTime - startTime);
        //执行sql脚本
        this.execDbScript(installProperties);
    }

    @Override
    public void installCluster(InstallProperties installProperties) throws Exception {
        String installName = installProperties.getInstallName();
        //安装时间
        long startInstallTime = System.currentTimeMillis();
        log.info("当前集群安装软件为为：{}，开始时间为：{}", installName, startInstallTime);
        List<String> connNameS = installProperties.getConnNameS();
        int connNameSize = connNameS.size();
        final CountDownLatch countDownLatch = new CountDownLatch(connNameSize);
        for (String connName : connNameS) {
            Runnable installClusterRunnable = new InstallCluster(connName, installProperties, this, countDownLatch);
            new Thread(installClusterRunnable, connName).start();
        }
        countDownLatch.await();
        long endInstallTime = System.currentTimeMillis();
        log.info("当前集群安装软件为为：{},结束时间为：{},共用时：{}毫秒", installName, endInstallTime, endInstallTime - startInstallTime);
    }


    private static class InstallCluster implements Runnable {
        private String connName;
        private InstallProperties installProperties;
        private GroupControlService groupControlService;
        private CountDownLatch countDownLatch;

        public InstallCluster(String connName, InstallProperties installProperties,
                              GroupControlService groupControlService, CountDownLatch countDownLatch) {
            this.connName = connName;
            this.installProperties = installProperties;
            this.groupControlService = groupControlService;
            this.countDownLatch = countDownLatch;
        }

        @Override
        public void run() {
            InstallProperties installPropertiesSon = new InstallProperties();
            try {
                installPropertiesSon.setModelEnum(installProperties.getModelEnum());
                installPropertiesSon.setConnName(connName);
                installPropertiesSon.setConnNameS(installProperties.getConnNameS());
                installPropertiesSon.setInstallName(installProperties.getInstallName());
                installPropertiesSon.setDirectory(installProperties.getDirectory());
                String installPathNum = installProperties.getInstallPathNumMap().get(connName);
                if (StringUtil.StringUtilsBylang3.isEmpty(installPathNum)) {
                    throw new BadRequestException("3400000002", "无法通过connName，找到对应的installNum");
                }
                installPropertiesSon.setInstallPathNum(installPathNum);
                installPropertiesSon.setLocalScriptPath(installProperties.getLocalScriptPath().concat(installPathNum));
                this.groupControlService.installSingle(installPropertiesSon);
            } catch (Exception e) {
                throw new RuntimeException(e);
            } finally {
                installProperties.getNoteMap().putAll(installPropertiesSon.getNoteMap());
                try {
                    countDownLatch.countDown();
                } catch (Exception e) {
                    throw new RuntimeException(e);
                }
            }
        }
    }

    @Override
    public void execScript(String connName, InstallProperties installProperties) throws Exception {
        if (installProperties.getInstallFlag()) {
            this.execScript(connName, installProperties.getInstallScriptPath());
            this.getJschService().execAllShell(Conn.buildExec(connName), "rm -rf ".concat(installProperties.getInstallScriptPath()));
        }
    }

    @Override
    public void execScript(String connName, String installScriptPath) throws Exception {
        this.getJschService().execAllShell(Conn.buildExec(connName), installScriptPath);
    }

    @Override
    public void execBeforeScript(String connName, InstallProperties installProperties) throws Exception {
        if (installProperties.getInstallBeforeFlag()) {
            this.execScript(connName, installProperties.getInstallBeforeScriptPath());
            this.getJschService().execAllShell(Conn.buildExec(connName), "rm -rf ".concat(installProperties.getInstallBeforeScriptPath()));
        }
    }

    @Override
    public void execDbScript(InstallProperties installProperties) throws Exception {
        if (installProperties.getInstallDbFlag()) {
            String connName = SessiontConnectionConfig.getRootConnName(installProperties.getConnName());
            //先启动mysql
            if (!this.jackStats("mysql", installProperties.getModelEnum().getCode())) {
                List<String> mysql = this.jackStart("mysql", installProperties.getModelEnum().getCode());
                log.info("MySQL启动日志为：{}", mysql);
            }
            TimeUnit.SECONDS.sleep(15);
            installProperties.getDbScriptPathList().stream().sorted(Comparator.naturalOrder());
            List<String> dbScriptList = new ArrayList<>();
            installProperties.getDbScriptPathList().stream().forEach(dbScript -> {
                dbScriptList.add("docker exec -i mysql8 mysql -uroot -pMySQL5726_root  < ".concat(dbScript));
            });
            this.getJschService().execAllShell(Conn.buildExec(connName), dbScriptList);
        }
    }

    @Override
    public Boolean stats(String softName, String systemName) throws Exception {
        log.info("----------查询状态----------softName：{}----------systemName：{}", softName, systemName);
        softName = this.concatSoftName(softName, systemName);
        JackSoftProperties.SoftProperties softProperties = this.getJackSoftPropertiesMap().get(softName);
        if (ObjectUtils.isEmpty(softProperties)) {
            log.warn("查询状态----------配置错误，请检查----------softName：{}----------systemName：{}", softName, systemName);
            return Boolean.FALSE;
        }
        String statsCmd = "";
        String execShell = "";
        String connName = "";
        List<String> containerNameList = null;
        LinkedHashMap<String, List<String>> connContainerNameMap = null;
        switch (softProperties.getModel()) {
            case 0:
                connName = softProperties.getConnName();
                this.execOtherCmd(BeforeAfterEnum.before, ModelEnum.stats, connName, softProperties);
                statsCmd = this.concatStats(softProperties.getContainerName());
                log.info("----------查询状态----------connName：{}----------softName：{}----------systemName：{}----------执行命令：【{}】", connName, softName, systemName, statsCmd);
                execShell = this.getJschService().execShell(Conn.buildExec(connName), statsCmd);
                log.info("----------查询状态----------connName：{}----------softName：{}----------systemName：{}----------返回数据：【{}】", connName, softName, systemName, execShell);
                this.execOtherCmd(BeforeAfterEnum.after, ModelEnum.stats, connName, softProperties);
                if (Boolean.TRUE.toString().equals(execShell)) {
                    return Boolean.TRUE;
                } else {
                    return Boolean.FALSE;
                }
            case 1:
                connName = softProperties.getConnName();
                this.execOtherCmd(BeforeAfterEnum.before, ModelEnum.stats, connName, softProperties);
                containerNameList = softProperties.getContainerNameList();
                if (ObjectUtils.isEmpty(containerNameList) || containerNameList.size() == 0) {
                    this.execOtherCmd(BeforeAfterEnum.after, ModelEnum.stats, connName, softProperties);
                    return Boolean.TRUE;
                }
                for (String containerName : softProperties.getContainerNameList()) {
                    statsCmd = this.concatStats(containerName);
                    log.info("----------查询状态----------connName：{}----------softName：{}----------systemName：{}----------执行命令：【{}】", connName, softName, systemName, statsCmd);
                    execShell = this.getJschService().execShell(Conn.buildExec(connName), statsCmd);
                    log.info("----------查询状态----------connName：{}----------softName：{}----------systemName：{}----------返回数据：【{}】", connName, softName, systemName, execShell);
                    if (!Boolean.TRUE.toString().equals(execShell)) {
                        this.execOtherCmd(BeforeAfterEnum.after, ModelEnum.stats, connName, softProperties);
                        return Boolean.FALSE;
                    }
                }
                this.execOtherCmd(BeforeAfterEnum.after, ModelEnum.stats, connName, softProperties);
                return Boolean.TRUE;
            case 2:
                connContainerNameMap = softProperties.getConnContainerNameMap();
                if (ObjectUtils.isEmpty(connContainerNameMap) || connContainerNameMap.size() == 0) {
                    return Boolean.TRUE;
                }
                for (String connNameByContainer : connContainerNameMap.keySet()) {
                    this.execOtherCmd(BeforeAfterEnum.before, ModelEnum.stats, connNameByContainer, softProperties);
                    containerNameList = softProperties.getConnContainerNameMap().get(connNameByContainer);
                    if (ObjectUtils.isEmpty(containerNameList) || containerNameList.size() == 0) {
                        this.execOtherCmd(BeforeAfterEnum.after, ModelEnum.stats, connNameByContainer, softProperties);
                        return Boolean.TRUE;
                    }
                    for (String containerName : containerNameList) {
                        statsCmd = this.concatStats(containerName);
                        log.info("----------查询状态----------connNameByContainer：{}----------softName：{}----------systemName：{}----------执行命令：【{}】", connNameByContainer, softName, systemName, statsCmd);
                        execShell = this.getJschService().execShell(Conn.buildExec(connNameByContainer), statsCmd);
                        log.info("----------查询状态----------connNameByContainer：{}----------softName：{}----------systemName：{}----------返回数据：【{}】", connNameByContainer, softName, systemName, execShell);
                        if (!Boolean.TRUE.toString().equals(execShell)) {
                            this.execOtherCmd(BeforeAfterEnum.after, ModelEnum.stats, connNameByContainer, softProperties);
                            return Boolean.FALSE;
                        }
                    }
                    this.execOtherCmd(BeforeAfterEnum.after, ModelEnum.stats, connNameByContainer, softProperties);
                }

                return Boolean.TRUE;
            default:
                log.warn("查询状态----------配置错误，请检查----------softName：{}----------systemName：{}", softName, systemName);
                return Boolean.FALSE;
        }
    }

    @Override
    public Boolean beforeStats(String softName, String systemName) throws Exception {
        log.info("----------查询前置状态----------softName：{}----------systemName：{}", softName, systemName);
        softName = this.concatSoftName(softName, systemName);
        JackSoftProperties.SoftProperties softProperties = this.getJackSoftPropertiesMap().get(softName);
        if (ObjectUtils.isEmpty(softProperties)) {
            log.warn("查询前置状态----------配置错误，请检查----------softName：{}----------systemName：{}", softName, systemName);
            return Boolean.FALSE;
        }
        if (ObjectUtils.isEmpty(softProperties.getBeforeSoftName()) || softProperties.getBeforeSoftName().size() == 0) {
            return Boolean.TRUE;
        }
        for (String beforeSoftName : softProperties.getBeforeSoftName()) {
            JackSoftProperties.SoftProperties beforeSoftProperties
                    = this.getJackSoftPropertiesMap().get(this.concatSoftName(beforeSoftName, systemName));
            if (ObjectUtils.isEmpty(beforeSoftProperties)) {
                log.warn("查询前置状态----------配置错误，请检查----------softName：{}----------systemName：{}", this.concatSoftName(beforeSoftName, systemName), systemName);
                return Boolean.FALSE;
            }
            //判断是否是docker部署
            if (beforeSoftProperties.getDockerFlag()) {
                return this.jackStats(beforeSoftName, systemName);
            } else {
                String beanName = beforeSoftProperties.getSoftName().concat(GROUP_CONTROL_SERVICE_IMPL);
                GroupControlService groupControlService = SpringUtil.getBean(beanName, GroupControlService.class);
                if (ObjectUtils.isEmpty(groupControlService)) {
                    log.info("无法找到BeanName为{}的bean", beanName);
                    return Boolean.FALSE;
                }
                return groupControlService.jackStats(beforeSoftName, systemName);
            }
        }
        return Boolean.TRUE;
    }

    @Override
    public Boolean afterStats(String softName, String systemName) throws Exception {
        log.info("----------查询后置状态----------softName：{}----------systemName：{}", softName, systemName);
        softName = this.concatSoftName(softName, systemName);
        JackSoftProperties.SoftProperties softProperties = this.getJackSoftPropertiesMap().get(softName);
        if (ObjectUtils.isEmpty(softProperties)) {
            log.warn("查询后置状态----------配置错误，请检查----------softName：{}----------systemName：{}", softName, systemName);
            return Boolean.FALSE;
        }
        if (ObjectUtils.isEmpty(softProperties.getAfterSoftName()) || softProperties.getAfterSoftName().size() == 0) {
            return Boolean.TRUE;
        }
        for (String afterSoftName : softProperties.getAfterSoftName()) {
            JackSoftProperties.SoftProperties afterSoftProperties
                    = this.getJackSoftPropertiesMap().get(this.concatSoftName(afterSoftName, systemName));
            if (ObjectUtils.isEmpty(afterSoftProperties)) {
                log.warn("查询后置状态----------配置错误，请检查----------softName：{}----------systemName：{}", this.concatSoftName(afterSoftName, systemName), systemName);
                return Boolean.FALSE;
            }
            //判断是否是docker部署
            if (afterSoftProperties.getDockerFlag()) {
                return this.jackStats(afterSoftName, systemName);
            } else {
                String beanName = afterSoftProperties.getSoftName().concat(GROUP_CONTROL_SERVICE_IMPL);
                GroupControlService groupControlService = SpringUtil.getBean(beanName, GroupControlService.class);
                if (ObjectUtils.isEmpty(groupControlService)) {
                    log.info("无法找到BeanName为{}的bean", beanName);
                    return Boolean.FALSE;
                }
                return groupControlService.jackStats(afterSoftName, systemName);
            }
        }
        return Boolean.TRUE;
    }

    @Override
    public List<String> start(String softName, String systemName) throws Exception {
        List<String> response = new ArrayList<>();
        log.info("----------启动----------softName：{}----------systemName：{}", softName, systemName);
        softName = this.concatSoftName(softName, systemName);
        JackSoftProperties.SoftProperties jackSoftProperties = this.getJackSoftPropertiesMap().get(softName);
        if (ObjectUtils.isEmpty(jackSoftProperties)) {
            log.warn("启动----------配置错误，请检查----------softName：{}----------systemName：{}", softName, systemName);
            return response;
        }
        String statsCmd = "";
        String execShell = "";
        String connName = jackSoftProperties.getConnName();
        List<String> containerNameList = null;
        LinkedHashMap<String, List<String>> connContainerNameMap = null;
        switch (jackSoftProperties.getModel()) {
            case 0:
                response.addAll(this.execOtherCmd(BeforeAfterEnum.before, ModelEnum.start, connName, jackSoftProperties));
                statsCmd = this.concatStart(jackSoftProperties.getContainerName());
                log.info("----------启动----------connName：{}----------softName：{}----------systemName：{}----------执行命令：【{}】", connName, softName, systemName, statsCmd);
                execShell = this.getJschService().execShell(Conn.buildExec(connName), statsCmd);
                log.info("----------启动----------connName：{}----------softName：{}----------systemName：{}----------返回数据：【{}】", connName, softName, systemName, execShell);
                response.add(execShell);
                response.addAll(this.execOtherCmd(BeforeAfterEnum.after, ModelEnum.start, connName, jackSoftProperties));
                return response;
            case 1:
                response.addAll(this.execOtherCmd(BeforeAfterEnum.before, ModelEnum.start, connName, jackSoftProperties));
                containerNameList = jackSoftProperties.getContainerNameList();
                if (ObjectUtils.isEmpty(containerNameList) || containerNameList.size() == 0) {
                    return response;
                }
                for (String containerName : jackSoftProperties.getContainerNameList()) {
                    statsCmd = this.concatStart(containerName);
                    log.info("----------启动----------connName：{}----------softName：{}----------systemName：{}----------执行命令：【{}】", connName, softName, systemName, statsCmd);
                    execShell = this.getJschService().execShell(Conn.buildExec(connName), statsCmd);
                    log.info("----------启动----------connName：{}----------softName：{}----------systemName：{}----------返回数据：【{}】", connName, softName, systemName, execShell);
                    response.add(execShell);
                }
                response.addAll(this.execOtherCmd(BeforeAfterEnum.after, ModelEnum.start, connName, jackSoftProperties));
                return response;
            case 2:
                connContainerNameMap = jackSoftProperties.getConnContainerNameMap();
                if (ObjectUtils.isEmpty(connContainerNameMap) || connContainerNameMap.size() == 0) {
                    return response;
                }
                for (String connNameByContainer : connContainerNameMap.keySet()) {
                    response.addAll(this.execOtherCmd(BeforeAfterEnum.before, ModelEnum.start, connNameByContainer, jackSoftProperties));
                    containerNameList = jackSoftProperties.getConnContainerNameMap().get(connNameByContainer);
                    if (ObjectUtils.isEmpty(containerNameList) || containerNameList.size() == 0) {
                        response.addAll(this.execOtherCmd(BeforeAfterEnum.after, ModelEnum.start, connNameByContainer, jackSoftProperties));
                        return response;
                    }
                    for (String containerName : containerNameList) {
                        statsCmd = this.concatStart(containerName);
                        log.info("----------启动----------connNameByContainer：{}----------softName：{}----------systemName：{}----------执行命令：【{}】", connNameByContainer, softName, systemName, statsCmd);
                        execShell = this.getJschService().execShell(Conn.buildExec(connNameByContainer), statsCmd);
                        log.info("----------启动----------connNameByContainer：{}----------softName：{}----------systemName：{}----------返回数据：【{}】", connNameByContainer, softName, systemName, execShell);
                        response.add(execShell);
                    }
                    response.addAll(this.execOtherCmd(BeforeAfterEnum.after, ModelEnum.start, connNameByContainer, jackSoftProperties));
                }

                return response;
            default:
                log.warn("启动----------配置错误，请检查----------softName：{}----------systemName：{}", softName, systemName);
                return response;
        }
    }

    @Override
    public List<String> beforeStart(String softName, String systemName) throws Exception {
        List<String> response = new ArrayList<>();
        log.info("----------启动前置----------softName：{}----------systemName：{}", softName, systemName);
        softName = this.concatSoftName(softName, systemName);
        JackSoftProperties.SoftProperties softProperties = this.getJackSoftPropertiesMap().get(softName);
        if (ObjectUtils.isEmpty(softProperties)) {
            log.warn("启动前置----------配置错误，请检查----------softName：{}----------systemName：{}", softName, systemName);
            return response;
        }
        if (ObjectUtils.isEmpty(softProperties.getBeforeSoftName()) || softProperties.getBeforeSoftName().size() == 0) {
            return response;
        }
        for (String beforeSoftName : softProperties.getBeforeSoftName()) {
            JackSoftProperties.SoftProperties beforeSoftProperties
                    = this.getJackSoftPropertiesMap().get(this.concatSoftName(beforeSoftName, systemName));
            if (ObjectUtils.isEmpty(beforeSoftProperties)) {
                log.warn("启动前置----------配置错误，请检查----------softName：{}----------systemName：{}", this.concatSoftName(beforeSoftName, systemName), systemName);
                return response;
            }
            //判断是否是docker部署
            if (beforeSoftProperties.getDockerFlag()) {
                response.addAll(this.jackStart(beforeSoftName, systemName));
            } else {
                String beanName = beforeSoftProperties.getSoftName().concat(GROUP_CONTROL_SERVICE_IMPL);
                GroupControlService groupControlService = SpringUtil.getBean(beanName, GroupControlService.class);
                if (ObjectUtils.isEmpty(groupControlService)) {
                    log.info("无法找到BeanName为{}的bean", beanName);
                    return response;
                }
                response.addAll(groupControlService.jackStart(beforeSoftName, systemName));
            }
        }
        return response;
    }

    @Override
    public List<String> afterStart(String softName, String systemName) throws Exception {
        List<String> response = new ArrayList<>();
        log.info("----------启动后置----------softName：{}----------systemName：{}", softName, systemName);
        softName = this.concatSoftName(softName, systemName);
        JackSoftProperties.SoftProperties softProperties = this.getJackSoftPropertiesMap().get(softName);
        if (ObjectUtils.isEmpty(softProperties)) {
            log.warn("启动后置----------配置错误，请检查----------softName：{}----------systemName：{}", softName, systemName);
            return response;
        }
        if (ObjectUtils.isEmpty(softProperties.getAfterSoftName()) || softProperties.getAfterSoftName().size() == 0) {
            return response;
        }
        for (String afterSoftName : softProperties.getAfterSoftName()) {
            JackSoftProperties.SoftProperties afterSoftProperties
                    = this.getJackSoftPropertiesMap().get(this.concatSoftName(afterSoftName, systemName));
            if (ObjectUtils.isEmpty(afterSoftProperties)) {
                log.warn("启动后置----------配置错误，请检查----------softName：{}----------systemName：{}", this.concatSoftName(afterSoftName, systemName), systemName);
                return response;
            }
            //判断是否是docker部署
            if (afterSoftProperties.getDockerFlag()) {
                response.addAll(this.jackStart(afterSoftName, systemName));
            } else {
                String beanName = afterSoftProperties.getSoftName().concat(GROUP_CONTROL_SERVICE_IMPL);
                GroupControlService groupControlService = SpringUtil.getBean(beanName, GroupControlService.class);
                if (ObjectUtils.isEmpty(groupControlService)) {
                    log.info("无法找到BeanName为{}的bean", beanName);
                    return response;
                }
                response.addAll(groupControlService.jackStart(afterSoftName, systemName));
            }
        }
        return response;
    }

    @Override
    public List<String> stop(String softName, String systemName) throws Exception {
        List<String> response = new ArrayList<>();
        log.info("----------停止----------softName：{}----------systemName：{}", softName, systemName);
        softName = this.concatSoftName(softName, systemName);
        JackSoftProperties.SoftProperties softProperties = this.getJackSoftPropertiesMap().get(softName);
        if (ObjectUtils.isEmpty(softProperties)) {
            log.warn("停止----------配置错误，请检查----------softName：{}----------systemName：{}", softName, systemName);
            return response;
        }
        String stopCmd = "";
        String execShell = "";
        String connName = softProperties.getConnName();
        List<String> containerNameList = null;
        LinkedHashMap<String, List<String>> connContainerNameMap = null;
        switch (softProperties.getModel()) {
            case 0:
                response.addAll(this.execOtherCmd(BeforeAfterEnum.before, ModelEnum.stop, connName, softProperties));
                stopCmd = this.concatStop(softProperties.getContainerName());
                log.info("----------停止----------sessionName：{}----------softName：{}----------systemName：{}----------执行命令：【{}】", connName, softName, systemName, stopCmd);
                execShell = this.getJschService().execShell(Conn.buildExec(connName), stopCmd);
                log.info("----------停止----------sessionName：{}----------softName：{}----------systemName：{}----------返回数据：【{}】", connName, softName, systemName, execShell);
                response.add(execShell);
                response.addAll(this.execOtherCmd(BeforeAfterEnum.after, ModelEnum.stop, connName, softProperties));
                return response;
            case 1:
                response.addAll(this.execOtherCmd(BeforeAfterEnum.before, ModelEnum.stop, connName, softProperties));
                containerNameList = softProperties.getContainerNameList();
                if (ObjectUtils.isEmpty(containerNameList) || containerNameList.size() == 0) {
                    return response;
                }
                for (String containerName : softProperties.getContainerNameList()) {
                    stopCmd = this.concatStop(containerName);
                    log.info("----------停止----------sessionName：{}----------softName：{}----------systemName：{}----------执行命令：【{}】", connName, softName, systemName, stopCmd);
                    execShell = this.getJschService().execShell(Conn.buildExec(connName), stopCmd);
                    log.info("----------停止----------sessionName：{}----------softName：{}----------systemName：{}----------返回数据：【{}】", connName, softName, systemName, execShell);
                    response.add(execShell);
                }
                response.addAll(this.execOtherCmd(BeforeAfterEnum.after, ModelEnum.stop, connName, softProperties));
                return response;
            case 2:
                connContainerNameMap = softProperties.getConnContainerNameMap();
                if (ObjectUtils.isEmpty(connContainerNameMap) || connContainerNameMap.size() == 0) {
                    return response;
                }
                for (String connNameByContainer : connContainerNameMap.keySet()) {
                    response.addAll(this.execOtherCmd(BeforeAfterEnum.before, ModelEnum.stop, connNameByContainer, softProperties));
                    containerNameList = connContainerNameMap.get(connNameByContainer);
                    if (ObjectUtils.isEmpty(containerNameList) || containerNameList.size() == 0) {
                        response.addAll(this.execOtherCmd(BeforeAfterEnum.after, ModelEnum.stop, connNameByContainer, softProperties));
                        return response;
                    }
                    for (String containerName : containerNameList) {
                        stopCmd = this.concatStop(containerName);
                        log.info("----------停止----------connNameByContainer：{}----------softName：{}----------systemName：{}----------执行命令：【{}】", connNameByContainer, softName, systemName, stopCmd);
                        execShell = this.getJschService().execShell(Conn.buildExec(connNameByContainer), stopCmd);
                        log.info("----------停止----------connNameByContainer：{}----------softName：{}----------systemName：{}----------返回数据：【{}】", connNameByContainer, softName, systemName, execShell);
                        response.add(execShell);
                    }
                    response.addAll(this.execOtherCmd(BeforeAfterEnum.after, ModelEnum.stop, connNameByContainer, softProperties));
                }
                return response;
            default:
                log.warn("停止----------配置错误，请检查----------softName：{}----------systemName：{}", softName, systemName);
                return response;
        }
    }

    @Override
    public List<String> beforeStop(String softName, String systemName) throws Exception {
        List<String> response = new ArrayList<>();
        log.info("----------停止前置----------softName：{}----------systemName：{}", softName, systemName);
        softName = this.concatSoftName(softName, systemName);
        JackSoftProperties.SoftProperties softProperties = this.getJackSoftPropertiesMap().get(softName);
        if (ObjectUtils.isEmpty(softProperties)) {
            log.warn("停止前置----------配置错误，请检查----------softName：{}----------systemName：{}", softName, systemName);
            return response;
        }
        if (ObjectUtils.isEmpty(softProperties.getBeforeSoftName()) || softProperties.getBeforeSoftName().size() == 0) {
            return response;
        }
        for (String beforeSoftName : softProperties.getBeforeSoftName()) {
            JackSoftProperties.SoftProperties beforeSoftProperties
                    = this.getJackSoftPropertiesMap().get(this.concatSoftName(beforeSoftName, systemName));
            if (ObjectUtils.isEmpty(beforeSoftProperties)) {
                log.warn("停止前置----------配置错误，请检查----------softName：{}----------systemName：{}", this.concatSoftName(beforeSoftName, systemName), systemName);
                return response;
            }
            //判断是否是docker部署
            if (beforeSoftProperties.getDockerFlag()) {

                response.addAll(this.jackStop(beforeSoftName, systemName));
            } else {
                String beanName = beforeSoftProperties.getSoftName().concat(GROUP_CONTROL_SERVICE_IMPL);
                GroupControlService groupControlService = SpringUtil.getBean(beanName, GroupControlService.class);
                if (ObjectUtils.isEmpty(groupControlService)) {
                    log.info("无法找到BeanName为{}的bean", beanName);
                    return response;
                }
                response.addAll(groupControlService.jackStop(beforeSoftName, systemName));
            }
        }
        return response;
    }

    @Override
    public List<String> afterStop(String softName, String systemName) throws Exception {
        List<String> response = new ArrayList<>();
        log.info("----------停止后置----------softName：{}----------systemName：{}", softName, systemName);
        softName = this.concatSoftName(softName, systemName);
        JackSoftProperties.SoftProperties softProperties = this.getJackSoftPropertiesMap().get(softName);
        if (ObjectUtils.isEmpty(softProperties)) {
            log.warn("停止后置----------配置错误，请检查----------softName：{}----------systemName：{}", softName, systemName);
            return response;
        }
        if (ObjectUtils.isEmpty(softProperties.getAfterSoftName()) || softProperties.getAfterSoftName().size() == 0) {
            return response;
        }
        for (String afterSoftName : softProperties.getAfterSoftName()) {
            JackSoftProperties.SoftProperties afterSoftProperties
                    = this.getJackSoftPropertiesMap().get(this.concatSoftName(afterSoftName, systemName));
            if (ObjectUtils.isEmpty(afterSoftProperties)) {
                log.warn("停止后置----------配置错误，请检查----------softName：{}----------systemName：{}", this.concatSoftName(afterSoftName, systemName), systemName);
                return response;
            }
            //判断是否是docker部署
            if (afterSoftProperties.getDockerFlag()) {

                response.addAll(this.jackStop(afterSoftName, systemName));
            } else {
                String beanName = afterSoftProperties.getSoftName().concat(GROUP_CONTROL_SERVICE_IMPL);
                GroupControlService groupControlService = SpringUtil.getBean(beanName, GroupControlService.class);
                if (ObjectUtils.isEmpty(groupControlService)) {
                    log.info("无法找到BeanName为{}的bean", beanName);
                    return response;
                }
                response.addAll(groupControlService.jackStop(afterSoftName, systemName));
            }
        }
        return response;
    }

    @Override
    public List<String> restart(String softName, String systemName) throws Exception {
        List<String> response = new ArrayList<>();
        log.info("----------重启----------softName：{}----------systemName：{}", softName, systemName);
        softName = this.concatSoftName(softName, systemName);
        JackSoftProperties.SoftProperties softProperties = this.getJackSoftPropertiesMap().get(softName);
        if (ObjectUtils.isEmpty(softProperties)) {
            log.warn("重启----------配置错误，请检查----------softName：{}----------systemName：{}", softName, systemName);
            return response;
        }
        String restatsCmd = "";
        String execShell = "";
        String connName = softProperties.getConnName();
        List<String> containerNameList = null;
        LinkedHashMap<String, List<String>> connContainerNameMap = null;
        switch (softProperties.getModel()) {
            case 0:
                response.addAll(this.execOtherCmd(BeforeAfterEnum.before, ModelEnum.restart, connName, softProperties));
                restatsCmd = this.concatReStart(softProperties.getContainerName());
                log.info("----------重启----------connName：{}----------softName：{}----------systemName：{}----------执行命令：【{}】", connName, softName, systemName, restatsCmd);
                execShell = this.getJschService().execShell(Conn.buildExec(connName), restatsCmd);
                log.info("----------重启----------connName：{}----------softName：{}----------systemName：{}----------返回数据：【{}】", connName, softName, systemName, execShell);
                response.add(execShell);
                response.addAll(this.execOtherCmd(BeforeAfterEnum.after, ModelEnum.restart, connName, softProperties));
                return response;
            case 1:
                response.addAll(this.execOtherCmd(BeforeAfterEnum.before, ModelEnum.restart, connName, softProperties));
                containerNameList = softProperties.getContainerNameList();
                if (ObjectUtils.isEmpty(containerNameList) || containerNameList.size() == 0) {
                    response.addAll(this.execOtherCmd(BeforeAfterEnum.after, ModelEnum.restart, connName, softProperties));
                    return response;
                }
                for (String containerName : softProperties.getContainerNameList()) {
                    restatsCmd = this.concatReStart(containerName);
                    log.info("----------重启----------connName：{}----------softName：{}----------systemName：{}----------执行命令：【{}】", connName, softName, systemName, restatsCmd);
                    execShell = this.getJschService().execShell(Conn.buildExec(connName), restatsCmd);
                    log.info("----------重启----------connName：{}----------softName：{}----------systemName：{}----------返回数据：【{}】", connName, softName, systemName, execShell);
                    response.add(execShell);
                }
                response.addAll(this.execOtherCmd(BeforeAfterEnum.after, ModelEnum.restart, connName, softProperties));
                return response;
            case 2:
                connContainerNameMap = softProperties.getConnContainerNameMap();
                if (ObjectUtils.isEmpty(connContainerNameMap) || connContainerNameMap.size() == 0) {
                    return response;
                }
                for (String connNameByContainer : connContainerNameMap.keySet()) {
                    response.addAll(this.execOtherCmd(BeforeAfterEnum.before, ModelEnum.restart, connNameByContainer, softProperties));
                    containerNameList = connContainerNameMap.get(connNameByContainer);
                    if (ObjectUtils.isEmpty(containerNameList) || containerNameList.size() == 0) {
                        response.addAll(this.execOtherCmd(BeforeAfterEnum.after, ModelEnum.restart, connNameByContainer, softProperties));
                        return response;
                    }
                    for (String containerName : containerNameList) {
                        restatsCmd = this.concatReStart(containerName);
                        log.info("----------重启----------connNameByContainer：{}----------softName：{}----------systemName：{}----------执行命令：【{}】", connNameByContainer, softName, systemName, restatsCmd);
                        execShell = this.getJschService().execShell(Conn.buildExec(connNameByContainer), restatsCmd);
                        log.info("----------重启----------connNameByContainer：{}----------softName：{}----------systemName：{}----------返回数据：【{}】", connNameByContainer, softName, systemName, execShell);
                        response.add(execShell);
                    }
                    response.addAll(this.execOtherCmd(BeforeAfterEnum.after, ModelEnum.restart, connNameByContainer, softProperties));
                }
                return response;
            default:
                log.warn("重启----------配置错误，请检查----------softName：{}----------systemName：{}", softName, systemName);
                return response;
        }
    }

    @Override
    public List<String> beforeRestart(String softName, String systemName) throws Exception {
        List<String> response = new ArrayList<>();
        log.info("----------重启前置----------softName：{}----------systemName：{}", softName, systemName);
        softName = this.concatSoftName(softName, systemName);
        JackSoftProperties.SoftProperties softProperties = this.getJackSoftPropertiesMap().get(softName);
        if (ObjectUtils.isEmpty(softProperties)) {
            log.warn("重启前置----------配置错误，请检查----------softName：{}----------systemName：{}", softName, systemName);
            return response;
        }
        if (ObjectUtils.isEmpty(softProperties.getBeforeSoftName()) || softProperties.getBeforeSoftName().size() == 0) {
            return response;
        }
        for (String beforeSoftName : softProperties.getBeforeSoftName()) {
            JackSoftProperties.SoftProperties beforeSoftProperties
                    = this.getJackSoftPropertiesMap().get(this.concatSoftName(beforeSoftName, systemName));
            if (ObjectUtils.isEmpty(beforeSoftProperties)) {
                log.warn("重启前置----------配置错误，请检查----------softName：{}----------systemName：{}", this.concatSoftName(beforeSoftName, systemName), systemName);
                return response;
            }
            //判断是否是docker部署
            if (beforeSoftProperties.getDockerFlag()) {
                response.addAll(this.jackReStart(beforeSoftName, systemName));
            } else {
                String beanName = beforeSoftProperties.getSoftName().concat(GROUP_CONTROL_SERVICE_IMPL);
                GroupControlService groupControlService = SpringUtil.getBean(beanName, GroupControlService.class);
                if (ObjectUtils.isEmpty(groupControlService)) {
                    log.info("无法找到BeanName为{}的bean", beanName);
                    return response;
                }
                response.addAll(groupControlService.jackReStart(beforeSoftName, systemName));
            }
        }
        return response;
    }

    @Override
    public List<String> afterRestart(String softName, String systemName) throws Exception {
        List<String> response = new ArrayList<>();
        log.info("----------重启后置----------softName：{}----------systemName：{}", softName, systemName);
        softName = this.concatSoftName(softName, systemName);
        JackSoftProperties.SoftProperties softProperties = this.getJackSoftPropertiesMap().get(softName);
        if (ObjectUtils.isEmpty(softProperties)) {
            log.warn("重启后置----------配置错误，请检查----------softName：{}----------systemName：{}", softName, systemName);
            return response;
        }
        if (ObjectUtils.isEmpty(softProperties.getAfterSoftName()) || softProperties.getAfterSoftName().size() == 0) {
            return response;
        }
        for (String afterSoftName : softProperties.getAfterSoftName()) {
            JackSoftProperties.SoftProperties afterSoftNameSoftProperties
                    = this.getJackSoftPropertiesMap().get(this.concatSoftName(afterSoftName, systemName));
            if (ObjectUtils.isEmpty(afterSoftNameSoftProperties)) {
                log.warn("重启后置----------配置错误，请检查----------softName：{}----------systemName：{}", this.concatSoftName(afterSoftName, systemName), systemName);
                return response;
            }
            //判断是否是docker部署
            if (afterSoftNameSoftProperties.getDockerFlag()) {
                response.addAll(this.jackReStart(afterSoftName, systemName));
            } else {
                String beanName = afterSoftNameSoftProperties.getSoftName().concat(GROUP_CONTROL_SERVICE_IMPL);
                GroupControlService groupControlService = SpringUtil.getBean(beanName, GroupControlService.class);
                if (ObjectUtils.isEmpty(groupControlService)) {
                    log.info("无法找到BeanName为{}的bean", beanName);
                    return response;
                }
                response.addAll(groupControlService.jackReStart(afterSoftName, systemName));
            }
        }
        return response;
    }

    @Override
    public void nonPassword(NonPasswordProperties nonPasswordProperties) throws Exception {
        //拼接配置文件
        StringBuffer stringBuffer = new StringBuffer("");
        StringBuffer stringBufferByRoot = new StringBuffer("");
        Map<String, SessiontConnectionConfig> sessiontConnectionConfigMap = this.getJschConfig().getSessiontConnectionConfigMap();
        nonPasswordProperties.getConnNameList().stream().forEach(connName -> {
            SessiontConnectionConfig sessiontConnectionConfig = sessiontConnectionConfigMap.get(connName);
            stringBuffer.append(connName).append("\t").append(sessiontConnectionConfig.getUserName())
                    .append("\t").append(sessiontConnectionConfig.getPassword()).append("\n");
            stringBuffer.append(sessiontConnectionConfig.getIp()).append("\t").append(sessiontConnectionConfig.getUserName())
                    .append("\t").append(sessiontConnectionConfig.getPassword()).append("\n");

            stringBufferByRoot.append(connName).append("\t").append(InstallServiceImpl.ROOT_USERNAME)
                    .append("\t").append(sessiontConnectionConfig.getRootPassword()).append("\n");
            stringBufferByRoot.append(sessiontConnectionConfig.getIp()).append("\t").append(InstallServiceImpl.ROOT_USERNAME)
                    .append("\t").append(sessiontConnectionConfig.getRootPassword()).append("\n");

        });


        String connName = nonPasswordProperties.getConnName();
        Resource resource = this.getResourceLoader().getResource("classpath:install/nonpassword/copykey.sh");
        File file = resource.getFile();
        String scriptName = "~/".concat(file.getName());
        String hostsName = "~/hosts";
        this.getJschService().upload(Conn.buildExec(connName), "~", file);
        this.getJschService().upload(Conn.buildExec(connName), "~",
                new ByteArrayInputStream(stringBuffer.toString().getBytes(StandardCharsets.UTF_8)), "hosts");
        this.getJschService().chmodInstall(Conn.buildExec(connName), scriptName);
        this.execScript(connName, scriptName);
        this.getJschService().execAllShell(Conn.buildExec(connName), "rm -rf ".concat(scriptName));
        this.getJschService().execAllShell(Conn.buildExec(connName), "rm -rf ".concat(hostsName));


        String rootConnName = SessiontConnectionConfig.getRootConnName(connName);
        this.getJschService().upload(Conn.buildExec(rootConnName), "~", file);
        this.getJschService().upload(Conn.buildExec(rootConnName), "~",
                new ByteArrayInputStream(stringBufferByRoot.toString().getBytes(StandardCharsets.UTF_8)), "hosts");
        this.getJschService().chmodInstall(Conn.buildExec(rootConnName), scriptName);
        this.execScript(rootConnName, scriptName);
        this.getJschService().execAllShell(Conn.buildExec(rootConnName), "rm -rf ".concat(scriptName));
        this.getJschService().execAllShell(Conn.buildExec(rootConnName), "rm -rf ".concat(hostsName));
    }
}
